package com.example.xcService.pojo.channels.impl;

import com.alibaba.fastjson.JSONObject;
import com.example.xcService.pojo.channels.ChannelResult;
import com.example.xcService.pojo.channels.ChannelService;
import com.example.xcService.pojo.tool.HttpTool;
import com.example.xcService.pojo.tool.XmlTool;
import lombok.extern.slf4j.Slf4j;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Pattern;

/*
* 季积
* */
@Slf4j
public class Plugin_ECARD_P040 implements ChannelService {


    private static final String DATE_FORMAT = "yyyyMMddHHmmssSSS"; // 日期时间格式
    private static final Random RANDOM = new Random();
    @Override
    public ChannelResult QueryBalance(JSONObject apiConfig) {
        System.out.println("成功调用了QueryBalance");
        return  ChannelResult.success("success");
    }

    @Override
    public ChannelResult Submit(JSONObject apiConfig, Map<String, Object> data) {
        try {
            String appId = apiConfig.getString("AppId");
            String accountVal = String.valueOf(data.get("AccountVal"));
            String accountValType = matchAccountType(accountVal);
            String key = apiConfig.getString("AppKey");
            String privateKey = apiConfig.getString("PrivateKey");
            String submitUrl = apiConfig.getString("SubmitUrl");
            String iv = apiConfig.getString("IV");

            LocalDateTime now = LocalDateTime.now();
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
            String formattedNow = now.format(formatter);
            String requestNo = generateSerialNumber();

            HashMap<String, String> xmlParams = new LinkedHashMap<>();
            xmlParams.put("AppID",appId);
            xmlParams.put("RequestNo",requestNo);//请求流水
            xmlParams.put("Action",accountValType);
            xmlParams.put("OutTradeNo",String.valueOf(data.get("ChannelOrderCode")));
            xmlParams.put("ProvideUin",accountVal);
            xmlParams.put("ProductId",String.valueOf(data.get("SUPProductId")));
            xmlParams.put("RightsType","3");
            xmlParams.put("RequestTime",formattedNow);
            String sign = sign(xmlParams, key);
            xmlParams.put("Sign",sign);
            String convertXML = convertXML(xmlParams);
            String encrypt = des3EncodeCBC(privateKey,iv,convertXML);

            HashMap<String, String> submitParams = new HashMap<>();
            submitParams.put("requestXML",encrypt);

            String respStr = HttpTool.sendPost(submitUrl, submitParams);
            JSONObject jsonObject = XmlTool.xml2Json(respStr);
            log.info("数据原串"+jsonObject.toJSONString());
            String responseXML = jsonObject.getString("responseXML");
            JSONObject parseObject = JSONObject.parseObject(responseXML);
            String msgCode = parseObject.getString("MsgCode");
            String msgContent = parseObject.getString("MsgContent");
            if (msgCode.equals("0000")) {
                return ChannelResult.IN_PROCESS("充值中");
            }else {
                return ChannelResult.FAILED(msgContent);
            }
        }catch (Exception e) {
            e.printStackTrace();
            log.error("季积提单接口错误：",e);
            return  ChannelResult.error("季积提单接口错误");
        }
    }

    @Override
    public ChannelResult Query(JSONObject apiConfig, Map<String, Object> data) {
        try {
            String appId = apiConfig.getString("AppId");
            String key = apiConfig.getString("AppKey");
            String privateKey = apiConfig.getString("PrivateKey");
            String queryUrl = apiConfig.getString("QueryUrl");
            String iv = apiConfig.getString("IV");

            LocalDateTime now = LocalDateTime.now();
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
            String formattedNow = now.format(formatter);
            String requestNo = generateSerialNumber();

            LinkedHashMap<String, String> encryptParams = new LinkedHashMap<>();
            encryptParams.put("AppID",appId);
            encryptParams.put("RequestNo",requestNo);
            encryptParams.put("OutTradeNo",String.valueOf(data.get("ChannelOrderCode")));
            encryptParams.put("RequestTime",formattedNow);

            String sign = sign(encryptParams, key);
            encryptParams.put("Sign",sign);

            String convertXML = convertXML(encryptParams);
            String encrypt = des3EncodeCBC(privateKey,iv,convertXML);

            HashMap<String, String> queryParams = new HashMap<>();
            queryParams.put("requestXML",encrypt);

            String respStr = HttpTool.sendPost(queryUrl, queryParams);
            JSONObject jsonObject = XmlTool.xml2Json(respStr);
            String responseXML = jsonObject.getString("responseXML");
            JSONObject parseObject = JSONObject.parseObject(responseXML);
            String msgCode = parseObject.getString("MsgCode");
            String msgContent = parseObject.getString("MsgContent");
            if (msgCode.equals("0000")) {
                String status = parseObject.getString("Status");
                if (status.equals("0")||status.equals("3")) {
                    return ChannelResult.IN_PROCESS("充值中");
                }
                if (status.equals("1")) {
                    return ChannelResult.success("充值成功");
                }
                if (status.equals("2")){
                    return ChannelResult.FAILED("充值失败#"+msgContent);
                }
            }
            return ChannelResult.error(msgContent);
        }catch (Exception e) {
            e.printStackTrace();
            log.error("季积查询接口错误：",e);
            return  ChannelResult.error("季积查询接口错误");
        }

    }


    @Override
    public ChannelResult Notify(JSONObject apiConfig, Map<String, Object> data) {
        System.out.println("成功调用了Notify");
        return  ChannelResult.success("success");
    }


    public static String des3EncodeCBC(String key, String keyiv, String data) throws Exception {
        byte[] str5 = des3EncodeCBC(key.getBytes(), keyiv.getBytes(), data.getBytes("utf-8"));
        return new BASE64Encoder().encode(str5);
    }

    /**
     * ECB加密,不要IV
     *
     * @param key 密钥
     * @param data 明文
     * @return Base64编码的密文
     * @throws Exception
     */
    public static byte[] des3EncodeECB(byte[] key, byte[] data) throws Exception {
        Key deskey = null;
        DESedeKeySpec spec = new DESedeKeySpec(key);
        SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("desede");
        deskey = keyfactory.generateSecret(spec);
        Cipher cipher = Cipher.getInstance("desede" + "/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, deskey);
        byte[] bOut = cipher.doFinal(data);
        return bOut;
    }

    /**
     * ECB解密,不要IV
     *
     * @param key 密钥
     * @param data Base64编码的密文
     * @return 明文
     * @throws Exception
     */
    public static byte[] ees3DecodeECB(byte[] key, byte[] data) throws Exception {
        Key deskey = null;
        DESedeKeySpec spec = new DESedeKeySpec(key);
        SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("desede");
        deskey = keyfactory.generateSecret(spec);
        Cipher cipher = Cipher.getInstance("desede" + "/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, deskey);
        byte[] bOut = cipher.doFinal(data);
        return bOut;
    }

    /**
     * CBC加密
     *
     * @param key 密钥
     * @param keyiv IV
     * @param data 明文
     * @return Base64编码的密文
     * @throws Exception
     */
    public static byte[] des3EncodeCBC(byte[] key, byte[] keyiv, byte[] data) throws Exception {
        Key deskey = null;
        DESedeKeySpec spec = new DESedeKeySpec(key);
        SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("desede");
        deskey = keyfactory.generateSecret(spec);
        Cipher cipher = Cipher.getInstance("desede" + "/CBC/PKCS5Padding");
        IvParameterSpec ips = new IvParameterSpec(keyiv);
        cipher.init(Cipher.ENCRYPT_MODE, deskey, ips);
        byte[] bOut = cipher.doFinal(data);
        return bOut;
    }

    public static String sign(Map<String, String> attributes, String key) {
        // 拼接键值对
        StringBuilder waitStr = new StringBuilder();
        for (Map.Entry<String, String> entry : attributes.entrySet()) {
            waitStr.append(entry.getValue());
        }
        waitStr.append(key); // 添加密钥
        // 计算MD5签名
        System.out.println(waitStr);
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(waitStr.toString().getBytes());
            byte[] digest = md.digest();
            StringBuilder sb = new StringBuilder();
            for (byte b : digest) {
                sb.append(String.format("%02x", b & 0xff)); // 将每个字节转换为两位16进制数
            }
            return sb.toString(); // 返回32位小写的签名
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("MD5 algorithm not available.", e);
        }
    }

    public static String convertXML(HashMap<String, String> attributes) {
        try {
            StringBuilder sb = new StringBuilder("<requestXML>");
            // 动态添加属性到根元素
            for (Map.Entry<String, String> entry : attributes.entrySet()) {
                sb.append("<").append(entry.getKey()).append(">")
                        .append(entry.getValue()).append("</")
                        .append(entry.getKey()).append(">");
            }
            sb.append("</requestXML>");
            log.info("拼接后"+sb.toString());
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return null; // 返回空字符串或处理异常的其他方式，取决于你的需求
        }
    }


    public static String matchAccountType(String account) {
        String phonePattern = "^1[3456789]\\d{9}$";
        String qqPattern = "^([1-3]\\d{4,9}|[1-9]\\d{4,8})$";
        Pattern phonePatternObj = Pattern.compile(phonePattern);
        Pattern qqPatternObj = Pattern.compile(qqPattern);
        if (phonePatternObj.matcher(account).matches()) {
            return "tob_provide_coupon"; // 手机号
        } else if (qqPatternObj.matcher(account).matches()) {
            return "direct_proivde"; // QQ号
        }else {
            return "tob_provide_coupon"; // 其他
        }
    }

    public static synchronized String generateSerialNumber() {
        SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
        String dateTimeStr = sdf.format(new Date()); // 获取当前日期时间字符串
        String randomStr = String.format("%05d", RANDOM.nextInt(99999)); // 生成6位随机数字字符串
        return dateTimeStr + randomStr; // 拼接成22位流水号
        }
    }
